//	Vec4f.cpp
#include "Cr.h"
#include <float.h>

#include "CrVec4f.h"

//	Handy constants. Note these may not be valid in C++ statically allocated
//	constructors (cos *they* are statically allocated)

namespace cr
{
	const Vec4f Vec4f::Xaxis(1,0,0,1);
	const Vec4f Vec4f::Yaxis(0,1,0,1);
	const Vec4f Vec4f::Zaxis(0,0,1,1);
	const Vec4f Vec4f::Waxis(0,0,0,1);

	const Vec4f Vec4f::XZaxis(1,0,1,1);
	const Vec4f Vec4f::YZaxis(0,1,1,1);
	const Vec4f Vec4f::XYaxis(1,1,0,1);

	const Vec4f Vec4f::NegXaxis(-1,1,1,1);
	const Vec4f Vec4f::NegYaxis(1,-1,1,1);
	const Vec4f Vec4f::NegZaxis(1,1,-1,1);

	const Vec4f Vec4f::One(1,1,1,1);
	const Vec4f Vec4f::Zero(0,0,0,1);
	const Vec4f Vec4f::Zero3(0,0,0,1);
	const Vec4f Vec4f::Zero4(0,0,0,0);

	const Vec4f Vec4f::FLT_MAX4(FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX);
	const Vec4f Vec4f::FLT_MIN4(FLT_MIN,FLT_MIN,FLT_MIN,FLT_MIN);

	Vec4f Vec4f::tangentXY() const
	{
		return Vec4f(-getY(), getX(), getZ(), getW());
	}

	Vec4f Vec4f::tangentYZ() const
	{
		return Vec4f(getX(), -getZ(), getY(), getW());
	}

	int Vec4f::majorAxis3() const
	{
		if (getX()>getY())
		{
			if (getX()>getZ())
				return 0;
			else
				return 2;
		}
		else
		{
			if (getY()>getZ())
				return 1;
			else
				return 2;
		}
	}

	int Vec4f::minorAxis3() const
	{
		if (getX()<getY())
		{
			if (getX()<getZ())
				return 0;
			else
				return 2;
		}
		else
		{
			if (getY()<getZ())
				return 1;
			else
				return 2;
		}
	}

	Vec4f Vec4f::tangentXZ() const
	{
		return Vec4f(getZ(),getY(),-getX(),getW());
	}

	float Vec4f::dotXZ(const Vec4f& v) const
	{
		return getX()*v.getX() + getZ()*v.getZ();
	}

	void Vec4f::normalise3()
	{
		float l = length3();
		if (l!=0)
			*this *= 1.0f/l;
	}

	void Vec4f::normalise4()
	{
		float l = length4();
		if (l!=0)
			*this *= 1.0f/l;
	}

	void Vec4f::normaliseXZ()
	{
		float l = lengthXZ();
		if (l!=0)
			*this *= 1.0f/l;
	}

	Vec4f Vec4f::cross3(const Vec4f& v) const
	{
		float x1=getX();
		float y1=getY();
		float z1=getZ();
		float x2=v.getX();
		float y2=v.getY();
		float z2=v.getZ();

		return Vec4f( y1*z2 - z1*y2, z1*x2 - x1*z2, x1*y2 - y1*x2);
	}

	Vec4f Vec4f::cross3_W0(const Vec4f& v) const
	{
		float x1=getX();
		float y1=getY();
		float z1=getZ();
		float x2=v.getX();
		float y2=v.getY();
		float z2=v.getZ();

		return Vec4f( y1*z2 - z1*y2, z1*x2 - x1*z2, x1*y2 - y1*x2, 0.0f);
	}

	float Vec4f::lengthXZ() const
	{
		float x=getX();
		float z=getZ();
		return sqrtf(x*x + z*z);
	}

	float Vec4f::sumElements3() const
	{
		return getX() + getY() + getZ();
	}


	float Vec4f::sumElements4() const
	{
		return getX() + getY() + getZ() + getW();
	}

	float Vec4f::sumElementsXZ() const
	{
		return getX() + getZ();
	}

	void Vec4f::cross3(const Vec4f& val1, const Vec4f& val2)
	{
		(*this) = val1.cross3(val2);
	}

	void Vec4f::cross3_W0(const Vec4f& val1, const Vec4f& val2)
	{
		(*this) = val1.cross3(val2);
		setW(0.0f);
	}

	Vec4f Vec4f::getXYZ_W0() const
	{
		Vec4f ret(*this);
		ret.setW(0);
		return ret;
	}

	Vec4f Vec4f::getXYZ_W1() const
	{
		Vec4f ret(*this);
		ret.setW(1);
		return ret;
	}

	inline float sign(float s)
	{
		if (s>0) return 1;
		if (s<0) return -1;
		return 0;
	}

	Vec4f Vec4f::sign4() const
	{
		return Vec4f(sign(getX()), sign(getY()), sign(getZ()), sign(getW()));
	}

}